-- drop function if exists sm_sc.fv_d_mx_ele_3d_2_2d_dloss_dindepdt(anyarray, int, int[2], int);
create or replace function sm_sc.fv_d_mx_ele_3d_2_2d_dloss_dindepdt
(
  i_dloss_ddepdt_2d        anyarray,
  i_len_dim_pin_ele int     ,  -- ((参与合并(但被定住元素顺序)的自变量)的维度)的长度   
  i_dims_from_to    int[2]  ,  -- 自变量参与合并两个维度。该参数第一个元素数字为 from 维度，第二个元素数字为 to 维度。合并后的新维度在 to 的顺序位置。当 from 与 to 为相邻维度时，[from, to] 等价于 [to, from]。
                               -- 枚举项包括，[1, 2] === [2, 1]; [2, 3] === [3, 2]; [1, 3]; [3, 1]
  i_dim_pin_ele     int        -- 被定住元素顺序的自变量旧维度。该旧维度下的元素顺序，将保留至新维度。i_dim_pin_ele 为 from 或 to，不能为其他值。
  
)
returns anyarray
as
$$
-- declare

begin
  if array_ndims(i_dloss_ddepdt_2d) <> 2
  then 
    raise exception 'ndims should be 2.';
  end if;
  
  if i_dim_pin_ele <> all(i_dims_from_to)
  then 
    raise exception 'the pin_ele dim must be one of from_to dims.';
  end if;
  
  if i_dims_from_to not in (array[1, 2], array[2, 1], array[2, 3], array[3, 2], array[1, 3], array[3, 1])
  then 
    raise exception 'unsupport other i_dims_from_to except [1, 2] === [2, 1]; [2, 3] === [3, 2]; [1, 3]; [3, 1].';
  end if;
  
  if array_length(i_dloss_ddepdt_2d, case when i_dims_from_to in (array[2, 3], array[3, 2], array[1, 3]) then 2 else 1 end) % i_len_dim_pin_ele <> 0
  then 
    raise exception 'unperfect length of i_dloss_ddepdt_2d for i_len_dim_pin_ele';
  end if;

  if i_dims_from_to in (array[1, 2], array[2, 1])
  then
    if i_dim_pin_ele = 1
    then 
      return 
        sm_sc.fv_opr_transpose_3d
        (
          sm_sc.fv_mx_ele_2d_2_3d
          (
            i_dloss_ddepdt_2d,
            i_len_dim_pin_ele,
            2
          ),
          array[1, 2]
        );
    else  -- -- elsif i_dim_pin_ele = 2
    -- -- then
      return 
        sm_sc.fv_mx_ele_2d_2_3d
        (
          i_dloss_ddepdt_2d,
          i_len_dim_pin_ele,
          2
        );
    end if;
  elsif i_dims_from_to = array[1, 3]
  then
    if i_dim_pin_ele = 1
    then
      return
        sm_sc.fv_opr_transpose_3d
        (
          sm_sc.fv_opr_transpose_3d
          (
            sm_sc.fv_mx_ele_2d_2_3d
            (
              i_dloss_ddepdt_2d,
              i_len_dim_pin_ele,
              1
            ),
            array[2, 3]
          ),
          array[1, 2]
        ) 
      ;
    else  -- -- elsif i_dim_pin_ele = 3
    -- -- then
      return 
        sm_sc.fv_opr_transpose_3d
        (
          sm_sc.fv_mx_ele_2d_2_3d
          (
            i_dloss_ddepdt_2d,
            i_len_dim_pin_ele,
            1
          ),
          array[1, 2]
        )
      ;
    end if;
  elsif i_dims_from_to = array[3, 1]
  then
    if i_dim_pin_ele = 1
    then
      return
        sm_sc.fv_opr_transpose_3d
        (
          sm_sc.fv_opr_transpose_3d
          (
            sm_sc.fv_mx_ele_2d_2_3d
            (
              i_dloss_ddepdt_2d,
              i_len_dim_pin_ele,
              2
            ),
            array[1, 2]
          ),
          array[2, 3]
        ) 
      ;
    else  -- -- elsif i_dim_pin_ele = 3
    -- -- then
      return 
        sm_sc.fv_opr_transpose_3d
        (
          sm_sc.fv_mx_ele_2d_2_3d
          (
            i_dloss_ddepdt_2d,
            i_len_dim_pin_ele,
            2
          ),
          array[2, 3]
        )
      ;
    end if;
  elsif i_dims_from_to in (array[2, 3], array[3, 2])
  then
    if i_dim_pin_ele = 2
    then
      return 
        sm_sc.fv_opr_transpose_3d
        (
          sm_sc.fv_mx_ele_2d_2_3d
          (
            i_dloss_ddepdt_2d,
            i_len_dim_pin_ele,
            1
          ),
          array[2, 3]
        );
    else  -- -- elsif i_dim_pin_ele = 3
    -- -- then 
      return 
        sm_sc.fv_mx_ele_2d_2_3d
        (
          i_dloss_ddepdt_2d,
          i_len_dim_pin_ele,
          1
        );
    end if;
  end if;
end
$$
language plpgsql stable
parallel safe
cost 100;
-- -- set search_path to sm_sc;
-- with cte_arr as
-- (
--   select 
--     array
--     [
--       [
--         [1, 2, 3, 4],
--         [5, 6, 7, 8],
--         [9, 10, 11, 12]
--       ],
--       [
--         [21, 22, 23, 24],
--         [25, 26, 27, 28],
--         [29, 30, 31, 32]
--       ]
--     ] as a_arr
-- )
-- select 
--   sm_sc.fv_mx_ele_3d_2_2d(a_arr, array[a_dims_from, a_dims_to], (array[a_dims_from, a_dims_to])[a_dim_pin_no]), 
--   array_length(a_arr, (array[a_dims_from, a_dims_to])[a_dim_pin_no]), 
--   array[a_dims_from, a_dims_to],
--   (array[a_dims_from, a_dims_to])[a_dim_pin_no],
--   sm_sc.fv_d_mx_ele_3d_2_2d_dloss_dindepdt
--   (
--     sm_sc.fv_mx_ele_3d_2_2d(a_arr, array[a_dims_from, a_dims_to], (array[a_dims_from, a_dims_to])[a_dim_pin_no]), 
--     array_length(a_arr, (array[a_dims_from, a_dims_to])[a_dim_pin_no]), 
--     array[a_dims_from, a_dims_to],
--     (array[a_dims_from, a_dims_to])[a_dim_pin_no]
--   ) as a_out
-- from cte_arr
--   , (select 1, 2 union all select 1, 3 union all select 2, 3 union all select 3, 1) tb_a_dims_from_to(a_dims_from, a_dims_to)
--   , generate_series(1, 2) tb_a_dim_pin_no(a_dim_pin_no)
-- order by a_dims_from, a_dims_to, a_dim_pin_no